﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace _20170206_Game_1_1
{
    class Game
    {
        private readonly Border border;
        private readonly List<GameNode> nodeList;
        private readonly List<GameNode> nodeWinnersList;
        private readonly Target target;
        private int x;
        private int y;
        private int width;
        private int height;
        private int nodeCount;
        private int numberRound = 0;
        Random r = new Random();

        public Game(int x, int y, int width, int height, char borderSymbol, char nodeSymbol, int nodeCount)
        {
            X = x;
            Y = y;
            Width = width;
            Height = height;
            NodeCount = nodeCount;

            border = new Border(this.x, this.y, borderSymbol, this.width + 2, this.height + 2);
            nodeList = new List<GameNode>();
            nodeWinnersList = new List<GameNode>();
            target = new Target(0, 0);
            PlayGame();
        }

        private int X
        {
            set
            {
                if (value < 0)
                    throw new ArgumentException("x < 0");
                x = value;
            }
        }

        private int Y
        {
            set
            {
                if (value < 0)
                    throw new ArgumentException("y < 0");
                y = value;
            }
        }

        private int Width
        {
            set
            {
                if (value < 3)
                    width = 3;
                else if (value > 60)
                    width = 60;
                else width = value;
            }
        }

        private int Height
        {
            set
            {
                if (value < 3)
                    height = 3;
                else if (value > 15)
                    height = 15;
                else height = value;
            }
        }

        private int NodeCount
        {
            set
            {
                if (width * height < nodeCount)
                    throw new ArgumentException("too much nodes");
                else if (value < 1)
                    throw new ArgumentException("nodeCount < 1");
                else nodeCount = value;
            }
        }

        private void InitNodeList(char nodeSymbol)
        {
            Random r = new Random();
            for (int i = 0; i < nodeCount; i++)
            {
                bool isCreated = false;
                while (!isCreated)
                {
                    int nodeX = r.Next(width) + x + 1;
                    int nodeY = r.Next(height) + y + 1;
                    if (!isOnNode(nodeX, nodeY))
                    {
                        nodeList.Add(new GameNode(nodeX, nodeY, nodeSymbol));
                        isCreated = true;
                    }
                }
            }
        }

        private void InitNodeList()
        {
            Random r = new Random();
            if (nodeCount > 9)
                nodeCount = 9;
            for (int i = 0; i < nodeCount; i++)
            {
                bool isCreated = false;
                while (!isCreated)
                {
                    int nodeX = r.Next(width) + x + 1;
                    int nodeY = r.Next(height) + y + 1;
                    if (!isOnNode(nodeX, nodeY))
                    {
                        nodeList.Add(new GameNode(nodeX, nodeY, (char)(i + 49)));
                        isCreated = true;
                    }
                }
            }
        }
       
        private void SetTarget()
        {
            while (true)
            {
                int nodeX = r.Next(width) + x + 1;
                int nodeY = r.Next(height) + y + 1;
                if (!isOnNode(nodeX, nodeY))
                {
                    target.SetX(nodeX);
                    target.SetY(nodeY);
                    break;
                }
            }
        }

        private void InitialDraw()
        {
            border.Draw();
            foreach (var node in nodeList)
            {
                node.Draw();
            }
            target.Draw();
        }

        private void PlayGame()
        {
            do
            {
                InitRound();
                PlayRound();
            }
            while (nodeWinnersList.Count > 1);
            Console.WriteLine();
            Console.WriteLine("Нод \'{0}\' победитель.", nodeWinnersList[0].Symbol);
            Thread.Sleep(1000);
        }

        private void PlayRound()
        {
            while (nodeList.Count > 1)
            {
                foreach (var node in nodeList)
                {
                    MoveNode(node);

                    if (isOnTarget(node.X, node.Y))
                    {
                        Thread.Sleep(200);
                        nodeWinnersList.Add(node);
                        nodeList.Remove(node);
                        target.Draw();
                        break;
                    }
                }
            }
            Console.SetCursorPosition(0, height + 3);
            Console.WriteLine("Нод \'{0}\' выбывает.", nodeList[0].Symbol);
            Thread.Sleep(1000);
        }

        private void InitRound()
        {
            Console.Clear();
            Console.WriteLine("Round {0}", ++numberRound);
            Thread.Sleep(1000);
            Console.Clear();
            if (numberRound == 1)
            {
                InitNodeList();
            }
            else
            {
                nodeList.Clear();
                MoveNodesToNodeList();
                nodeWinnersList.Clear();
            }
            SetTarget();
            InitialDraw();
        }

        private void MoveNodesToNodeList()
        {
            //nodeWinnersList, nodeList
            foreach (var node in nodeWinnersList)
            {
                bool isMoved = false;
                while (!isMoved)
                {
                    int nodeX = r.Next(width) + x + 1;
                    int nodeY = r.Next(height) + y + 1;
                    if (!isOnNode(nodeX, nodeY))
                    {
                        nodeList.Add(node);
                        isMoved = true;
                    }
                }
            }
        }

        private void MoveNode(GameNode node)
        {
            //0 - left
            //1 - up
            //2 - right
            //3 - down
            int choise = r.Next(4);
            Thread.Sleep(200);
            node.Clear();
            switch (choise)
            {
                case 0:
                    if (isOnField(node.X - 1, node.Y) && !isOnNode(node.X - 1, node.Y))
                    {
                        node.MoveLeft();
                        node.Draw();
                    }
                    else
                        node.SetRainbowColor();
                    break;
                case 1:
                    if (isOnField(node.X, node.Y - 1) && !isOnNode(node.X, node.Y - 1))
                    {
                        node.MoveUp();
                        node.Draw();
                    }
                    else
                        node.SetRainbowColor();
                    break;
                case 2:
                    if (isOnField(node.X + 1, node.Y) && !isOnNode(node.X + 1, node.Y))
                    {
                        node.MoveRight();
                        node.Draw();
                    }
                    else
                        node.SetRainbowColor();
                    break;
                case 3:
                    if (isOnField(node.X, node.Y + 1) && !isOnNode(node.X, node.Y + 1))
                    {
                        node.MoveDown();
                        node.Draw();
                    }
                    else
                        node.SetRainbowColor();
                    break;
            }
        }

        private bool isOnNode(int x, int y)
        {
            foreach (var node in nodeList)
                if (node.X == x && node.Y == y)
                    return true;
            return false;
        }

        private bool isOnField(int x, int y)
        {
            if (x <= this.x || x > width) return false;
            if (y <= this.y || y > height) return false;
            return true;
        }

        private bool isOnTarget(int x, int y)
        {
            if (target.X == x && target.Y == y)
                    return true;
            return false;
        }

    }
}
